﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VBFOOL.MediaPlayer.Core.Interface;
using System.Windows.Media;
namespace VBFOOL.MediaPlayer.MKV
{
    public class MKVFileThumbSource : IInputSource
    {
        public MKVFileThumbSource(LibEBML.Common.Matroska document)
        {
            this.Document = document;
            TimeCodeScale = Document.Segment.Info.TimecodeScale / 100;
        }
        public string Title
        {
            get
            {
                if (Document != null)
                {
                    return Document.Segment.Info.Title;
                }
                else
                {
                    return "";
                }
            }
        }

        public void ChangeAudioTrack(MediaStreamDescription desc)
        {
            throw new NotSupportedException();
        }

        public LibEBML.Common.Matroska Document { get; protected set; }
        long TimeCodeScale = 10000;
        public bool BuildStreams()
        {
            m_Tracks.Clear();
            foreach (var entry in Document.Segment.Tracks)
            {
                switch (entry.TrackType)
                {
                    case 1:
                        var c = m_Codecs.Where(m => m.SupportCodecID(entry.CodecID)).FirstOrDefault();
                        if (c != null)
                        {
                            MKVThumbTrack msv = new MKVThumbTrack(entry, MediaStreamType.Video, c.CreateCodecFilter());
                            if (VideoTrackID <= 0)
                            {
                                VideoTrackID = entry.TrackNumber;
                                m_Video = new MKVThumbStream() { CurrentTrack = msv };

                            }
                            m_Tracks.Add(msv);
                        }
                        break;
                    default:
                        continue;
                }

            }
            if (Document.Segment.Cues != null && Document.Segment.Cues.Count > 0)
            {
                var th = Document.Segment.Cues[1];
                var lt = th.CueTrackPositions[0].ClusterPosition + Document.Segment.SeekPosition;
                for (int i = 0; i < Document.Segment.Clusters.Count; i++)
                {
                    if (Document.Segment.Clusters[i].ClusterPosition == lt)
                    {
                        CurrentClusterID = i;
                        break;
                    }
                }
            }


            ProcessCluster();
            return true;
        }

        public IEnumerable<ISubtitleReader> Subtitles { get { return null; } }

        List<MKVThumbTrack> m_Tracks = new List<MKVThumbTrack>();
        public IEnumerable<IMediaTrack> Tracks
        {
            get
            {
                return m_Tracks as IEnumerable<IMediaTrack>;
            }
        }

        List<ICodecFactory> m_Codecs = new List<ICodecFactory>();

        public IList<ICodecFactory> Codecs
        {
            get { return m_Codecs; }
        }

        public bool CanSeek
        {
            get { return false; }
        }

        public decimal Duration
        {
            get { return 0; }
        }
        MKVThumbStream m_Video = null;
        int VideoTrackID = -1;
        public IMediaStream AudioStream { get { return null; } }
        public IMediaStream VideoStream { get { return m_Video; } }

        void ReadCluster(int ClusterID)
        {
            var cls = Document.Segment.Clusters;
            var cluster = cls[ClusterID];
            foreach (var item in cluster.Blocks)
            {
                if (item.TrackNumber == VideoTrackID)//Video
                {
                    m_Video.block = item;
                    break;
                }
            }
        }

        int CurrentClusterID;
        private void ProcessCluster()
        {
            ReadCluster(CurrentClusterID);
        }

        public long Seek(long SeekToTime)
        {
            return 0;
        }

    }
    class MKVThumbTrack : IMediaTrack
    {
        internal LibEBML.Common.TrackEntry entry;

        internal MKVThumbTrack(LibEBML.Common.TrackEntry track, MediaStreamType mediaStreamType, ICodecFilter codecFilter)
        {
            // TODO: Complete member initialization
            this.entry = track;
            Dictionary<string, object> obj = new Dictionary<string, object>();
            obj["CodecPrivateData"] = track.CodecPrivate;
            obj["Width"] = track.Video.PixelWidth;
            obj["Height"] = track.Video.PixelHeight;
            this.Description = new MediaStreamDescription(mediaStreamType, codecFilter.GetCodecPrivateData(obj));
            this.Codec = codecFilter;
            if (track.ContentEncodings != null && track.ContentEncodings.Count > 0)
            {
                var ce = track.ContentEncodings[0];
                if (ce.ContentEncodingType == 0)
                {
                    if (ce.Compression.ContentCompAlgo == 3)
                    {
                        CompressHeader = ce.Compression.ContentCompSettings;
                    }
                }
            }
        }
        internal byte[] CompressHeader = null;
        public MediaStreamDescription Description
        {
            get;
            internal set;
        }

        public ICodecFilter Codec
        {
            get;
            internal set;
        }

        public IInputSource Source
        {
            get;
            internal set;
        }
    }
    class MKVThumbStream : IMediaStream
    {

        public IInputSource Source
        {
            get;
            internal set;
        }

        public IMediaTrack CurrentTrack
        {
            get;
            internal set;
        }
        internal LibEBML.Common.SimpleBlock block = null;
        int i = 0;
        public Core.FrameData GetFrame()
        {
            var item = new Core.FrameData() { };
            if (block != null)
            {
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                var tc = CurrentTrack as MKVThumbTrack;
                var p = tc.entry.DefaultDuration / 100;
                var dts = block.GetBlockData(tc.CompressHeader)[0];
                var desc = tc.Codec.Translate(dts, 0, dts.Length);
                ms.Write(desc, 0, desc.Length);
                item.Data = ms;
                item.Length = ms.Length;
                item.Duration = p;
                item.TimeCode = i * p;
                ms.Position = 0;
                i++;
            }
            return item;
        }

        public double BufferProgress
        {
            get { return 1; }
        }
    }
}
